package com.lwl.mini.parsing;

import com.lwl.mini.builder.BuilderException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.InputSource;

import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

/**
 * @author lwl
 * @create 2022/4/9 12:44
 */
public class XPathParser {
    public Document document;
    public XPath xPath;

    public XPathParser(InputSource reader) {
        Document document = createDocument(reader);
        this.document = document;
        XPathFactory factory = XPathFactory.newInstance();
        this.xPath = factory.newXPath();
    }

    public Document createDocument(InputSource inputSource){
        // important:this must only be called after common constructor
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            //为true则在生成的解析器在解析文档时验证文档
            factory.setValidating(true);
            //对XML命名空间的支持
            factory.setNamespaceAware(false);
            //忽略注释
            factory.setIgnoringComments(true);
            //不消除解析时的空格
            factory.setIgnoringElementContentWhitespace(false);
            DocumentBuilder builder = factory.newDocumentBuilder();
            builder.setErrorHandler(new ErrorHandler() {
                @Override
                public void warning(SAXParseException exception) throws SAXException {
                }

                @Override
                public void error(SAXParseException exception) throws SAXException {
                    throw exception;
                }

                @Override
                public void fatalError(SAXParseException exception) throws SAXException {
                    throw exception;
                }
            });
            return builder.parse(inputSource);
        }catch (Exception e){
            throw new BuilderException("Error creating document instance . Cause: "+e,e);
        }
    }



    /**
     * 解析Node节点
     */
    public  XNode evalNode(String expression){
        return evalNode(document,expression);
    }

    /**
     * @param root xml文档对象Document;
     * @return XNode节点
     */
    public  XNode evalNode(Object root,String expression){
        Node node = (Node)evalNode(root,expression, XPathConstants.NODE);
        if(node == null){
            return null;
        }
        return new XNode(node,this);
    }

    public Object evalNode(Object root, String expression, QName returnType){
        try {
            return xPath.evaluate(expression,root,returnType);
        } catch (XPathExpressionException e) {
            throw new BuilderException("The error cause:"+e,e);
        }
    }
}
